package it.tukano.io;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Utility to store some data in memory, to read and write from/to memory and so on.
 * @author pgi
 */
public class MemBuffer {

    /**
     * Creates a new empty buffer
     * @return a new empty buffer
     */
    public static MemBuffer newInstance() {
        return new MemBuffer();
    }

    /**
     * Creates a new filled buffer
     * @param data the buffer's data
     * @return the buffer
     */
    public static MemBuffer newInstanceFromBytes(byte[] data) {
        return new MemBuffer(data);
    }

    /**
     * Creates a new filled buffer with a set of hex-encoded bytes
     * @param hex the hex byte sequence
     * @return the buffer
     */
    public static MemBuffer newInstanceFromHexBytes(String hex) {
        return new MemBuffer(BinaryUtilities.fromHexString(hex));
    }

    private ByteArrayOutputStream buffer;

    /**
     * Instance initializer
     */
    protected MemBuffer() {
        buffer = new ByteArrayOutputStream();
    }
    
    /**
     * Instance initializer
     * @param data initial data of the buffer
     */
    protected MemBuffer(byte[] data) {
        buffer = new ByteArrayOutputStream();
        try {
            buffer.write(data);
        } catch (IOException ex) {
            Logger.getLogger(MemBuffer.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * Returns the stream used to append bytes to the buffer
     * @return the stream
     */
    public OutputStream getOutputStream() {
        return buffer;
    }

    /**
     * Returns the stream used to read data from the buffer (alwasy starts at 0)
     * @return the input stream
     */
    public InputStream getInputStream() {
        return new ByteArrayInputStream(getBytes());
    }

    /**
     * Returns the contents of this buffer as an hex-encoded byte sequence
     * @return the hex sequence
     */
    public String getHexString() {
        return BinaryUtilities.toHexString(getBytes());
    }

    /**
     * Returns the contents of this buffer as a text
     * @param charsetName the charset name. Can be null (default used)
     * @return the text
     */
    public String getString(String charsetName) {
        Charset charset = charsetName == null ? Charset.defaultCharset() : Charset.forName(charsetName);
        return charset.decode(ByteBuffer.wrap(getBytes())).toString();
    }

    /**
     * Returns the bytes in this buffer (a copy)
     * @return the bytes in this buffer
     */
    public byte[] getBytes() {
        return buffer.toByteArray();
    }

    public DataOutputStream newDataOutput() {
        return new DataOutputStream(buffer);
    }
}
